using System.Diagnostics;

namespace muduoDotNet
{
    /// <summary>
    /// TimeStamp类，表示时间戳
    /// </summary>
    public struct TimeStamp : IComparable<TimeStamp>, IEquatable<TimeStamp>
    {
        private const long kMicroSecondsPerSecond = 1000 * 1000;
        private long _microSecondsSinceEpoch;

        public TimeStamp(long microSecondsSinceEpoch = 0)
        {
            _microSecondsSinceEpoch = microSecondsSinceEpoch;
        }

        /// <summary>
        /// 获取当前时间戳
        /// </summary>
        /// <returns>当前时间戳</returns>
        public static TimeStamp Now()
        {
            // 使用Stopwatch获取高精度时间
            var now = Stopwatch.GetTimestamp();
            var frequency = Stopwatch.Frequency;
            var microSeconds = (long)(now * kMicroSecondsPerSecond / frequency);
            return new TimeStamp(microSeconds);
        }

        /// <summary>
        /// 获取无效时间戳
        /// </summary>
        public static TimeStamp Invalid => new TimeStamp();

        /// <summary>
        /// 判断时间戳是否有效
        /// </summary>
        public bool IsValid => _microSecondsSinceEpoch > 0;

        /// <summary>
        /// 获取从纪元开始的微秒数
        /// </summary>
        public long MicroSecondsSinceEpoch => _microSecondsSinceEpoch;

        /// <summary>
        /// 获取从纪元开始的秒数
        /// </summary>
        public double SecondsSinceEpoch => _microSecondsSinceEpoch / (double)kMicroSecondsPerSecond;

        /// <summary>
        /// 转换为DateTime
        /// </summary>
        public DateTime ToDateTime()
        {
            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return epoch.AddTicks(_microSecondsSinceEpoch * 10);
        }

        /// <summary>
        /// 添加秒数
        /// </summary>
        /// <param name="seconds">要添加的秒数</param>
        /// <returns>新的时间戳</returns>
        public TimeStamp AddSeconds(double seconds)
        {
            long microSeconds = (long)(seconds * kMicroSecondsPerSecond);
            return new TimeStamp(_microSecondsSinceEpoch + microSeconds);
        }

        /// <summary>
        /// 添加毫秒数
        /// </summary>
        /// <param name="milliseconds">要添加的毫秒数</param>
        /// <returns>新的时间戳</returns>
        public TimeStamp AddMilliseconds(double milliseconds)
        {
            long microSeconds = (long)(milliseconds * 1000);
            return new TimeStamp(_microSecondsSinceEpoch + microSeconds);
        }

        #region 比较运算符

        public int CompareTo(TimeStamp other)
        {
            return _microSecondsSinceEpoch.CompareTo(other._microSecondsSinceEpoch);
        }

        public bool Equals(TimeStamp other)
        {
            return _microSecondsSinceEpoch == other._microSecondsSinceEpoch;
        }

        public override bool Equals(object obj)
        {
            if (obj is TimeStamp)
            {
                return Equals((TimeStamp)obj);
            }
            return false;
        }

        public override int GetHashCode()
        {
            return _microSecondsSinceEpoch.GetHashCode();
        }

        public static bool operator ==(TimeStamp left, TimeStamp right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(TimeStamp left, TimeStamp right)
        {
            return !left.Equals(right);
        }

        public static bool operator <(TimeStamp left, TimeStamp right)
        {
            return left._microSecondsSinceEpoch < right._microSecondsSinceEpoch;
        }

        public static bool operator <=(TimeStamp left, TimeStamp right)
        {
            return left._microSecondsSinceEpoch <= right._microSecondsSinceEpoch;
        }

        public static bool operator >(TimeStamp left, TimeStamp right)
        {
            return left._microSecondsSinceEpoch > right._microSecondsSinceEpoch;
        }

        public static bool operator >=(TimeStamp left, TimeStamp right)
        {
            return left._microSecondsSinceEpoch >= right._microSecondsSinceEpoch;
        }

        public static TimeStamp operator +(TimeStamp left, TimeSpan right)
        {
            long microSeconds = (long)(right.TotalMilliseconds * 1000);
            return new TimeStamp(left._microSecondsSinceEpoch + microSeconds);
        }

        public static TimeStamp operator -(TimeStamp left, TimeSpan right)
        {
            long microSeconds = (long)(right.TotalMilliseconds * 1000);
            return new TimeStamp(left._microSecondsSinceEpoch - microSeconds);
        }

        #endregion

        public override string ToString()
        {
            return SecondsSinceEpoch.ToString("0.000000");
        }
    }
}